package se.dolkow.skola.datasakerhet.server;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.logging.Logger;

import javax.net.ssl.SSLSocket;

import se.dolkow.skola.datasakerhet.server.storage.BoundStorage;
import se.dolkow.skola.datasakerhet.server.storage.Nurse;
import se.dolkow.skola.datasakerhet.server.storage.Patient;
import se.dolkow.skola.datasakerhet.server.storage.PermissionDeniedException;
import se.dolkow.skola.datasakerhet.server.storage.Record;

public class Session {
	private final BoundStorage storage;
	private final Logger log;
	
	private final ObjectOutputStream out; 
	private final ObjectInputStream in;

	public Session(BoundStorage storage, SSLSocket socket) throws IOException {
		this.storage = storage;
		this.log = Logger.getLogger("se.dolkow.skola.datasakerhet.server.storage");
		this.out = new ObjectOutputStream(socket.getOutputStream());
		this.in = new ObjectInputStream(socket.getInputStream());
		
		out.flush();
	}

	public void handle() throws IOException {
		if (storage.getUser() == null) {
			out.writeUTF("morr!");
			out.flush();
			return;
		}
		
		out.writeUTF("Välkommen " + storage.getUser() + "!");
		out.flush();
		
		try {
			while(true) {
				String cmd = in.readUTF();
				Response response = fail("Invalid command \"" + cmd + "\".");
				try {
					if(cmd.equals("list")) {
						response = cmdList();
					} else if(cmd.equals("get")) {
						response = cmdGet();
					} else if(cmd.equals("create")) {
						response = cmdCreate();
					} else if(cmd.equals("delete")) {
						response = cmdDelete();
					} else if(cmd.equals("set")) {
						response = cmdSet();
					}
				} catch (PermissionDeniedException pde) {
					response = permissionDenied();
				}
				out.writeInt(response.status);
				out.writeUTF(response.msg);
				out.flush();
			}
		} catch (SocketException e) {
			log.info("SocketException in session with " + storage.getUser());
		} catch (EOFException e) {
			log.info(storage.getUser() + " disconnected.");
		}
	}
	
	private Response cmdList() {
		ArrayList<Record> list = storage.getRecords();
		String text = "No available journals.";
		if (list.size() > 0) {
			StringBuilder sb = new StringBuilder();
			for(Record r: list) {
				sb.append(r.toString() + "\n");
			}
			text = sb.toString().trim();
		}
		
		return success(text);
	}
	
	private Response cmdGet() throws IOException, PermissionDeniedException {
		int id = in.readInt();
		Record r = storage.getRecord(id);
		if (r == null) {
			return fail("Record #" + id + " not found.");
		}
		return success(storage.getContent(r));
	}
	
	private Response cmdCreate() throws IOException, PermissionDeniedException {
		String pname = in.readUTF();
		String nname = in.readUTF();
		Patient p = storage.getPatient(pname);
		Nurse n = storage.getNurse(nname);
		if (p == null) {
			return fail("No such patient.");
		} else if (n == null) {
			return fail("No such nurse.");
		}
		Record r = storage.createRecord(p, n);
		return success("Created record #" + r.getId());
	}
	
	private Response cmdSet() throws IOException, PermissionDeniedException {
		Integer id = in.readInt();
		String text = in.readUTF();
		
		Record r = storage.getRecord(id);
		if (r == null) {
			return fail("No such record.");
		}
		storage.setContent(r, text);
		
		return success("Stored new content for record #" + id);
	}

	private Response cmdDelete() throws IOException, PermissionDeniedException {
		Integer id = in.readInt();
		Record r = storage.getRecord(id);
		if (r == null) {
			return fail("No such record.");
		}
		storage.deleteRecord(r);
		return success("Deleted record #" + id);
	}
	
	private static Response fail(String msg) {
		return new Response(2, msg);
	}
	
	private static Response success(String msg) {
		return new Response(0, msg);
	}
	
	private static Response permissionDenied(String msg) {
		return new Response(1, msg);
	}
	
	private static Response permissionDenied() {
		return permissionDenied("Permission Denied.");
	}
	
	private static class Response {
		final int status;
		final String msg;
		
		Response(int status, String msg) {
			this.status = status;
			this.msg = msg;
		}
	}

}
